From: Jan Beulich Date: Fri, 10 Jul 2015 10:36:24 +0000 (+0200) Subject: x86/MSI: fix guest unmasking when handling IRQ via event channel X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~2843 X-Git-Url: https://dgit.raspbian.org/%22http:/www.example.com/cgi/%22https:/%22bookmarks:/%22man:///%22http:/www.example.com/cgi/%22https:/%22bookmarks:/%22man:/?a=commitdiff_plain;h=84d6add5593d865736831d150da7c38588f669f6;p=xen.git x86/MSI: fix guest unmasking when handling IRQ via event channel Rather than assuming only PV guests need special treatment (and dealing with that directly when an IRQ gets set up), keep all guest MSI IRQs masked until either the (HVM) guest unmasks them via vMSI or the (PV, PVHVM, or PVH) guest sets up an event channel for it. To not further clutter the common evtchn_bind_pirq() with x86-specific code, introduce an arch_evtchn_bind_pirq() hook instead. Reported-by: Sander Eikelenboom Signed-off-by: Jan Beulich Tested-by: Sander Eikelenboom Reviewed-by: Andrew Cooper Acked-by: Ian Campbell --- diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c index fe1ee333b8..78e3f2e845 100644 --- a/xen/arch/x86/irq.c +++ b/xen/arch/x86/irq.c @@ -2502,6 +2502,25 @@ int unmap_domain_pirq_emuirq(struct domain *d, int pirq) return ret; } +void arch_evtchn_bind_pirq(struct domain *d, int pirq) +{ + int irq = domain_pirq_to_irq(d, pirq); + struct irq_desc *desc; + unsigned long flags; + + if ( irq <= 0 ) + return; + + if ( is_hvm_domain(d) ) + map_domain_emuirq_pirq(d, pirq, IRQ_PT); + + desc = irq_to_desc(irq); + spin_lock_irqsave(&desc->lock, flags); + if ( desc->msi_desc ) + guest_mask_msi_irq(desc, 0); + spin_unlock_irqrestore(&desc->lock, flags); +} + bool_t hvm_domain_use_pirq(const struct domain *d, const struct pirq *pirq) { return is_hvm_domain(d) && pirq && diff --git a/xen/arch/x86/msi.c b/xen/arch/x86/msi.c index a8923fcfdb..d930f8f0f7 100644 --- a/xen/arch/x86/msi.c +++ b/xen/arch/x86/msi.c @@ -422,10 +422,7 @@ void guest_mask_msi_irq(struct irq_desc *desc, bool_t mask) static unsigned int startup_msi_irq(struct irq_desc *desc) { - bool_t guest_masked = (desc->status & IRQ_GUEST) && - is_hvm_domain(desc->msi_desc->dev->domain); - - msi_set_mask_bit(desc, 0, guest_masked); + msi_set_mask_bit(desc, 0, !!(desc->status & IRQ_GUEST)); return 0; } diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index 679618aa9d..7640e30ef8 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -503,10 +503,7 @@ static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind) bind->port = port; -#ifdef CONFIG_X86 - if ( is_hvm_domain(d) && domain_pirq_to_irq(d, pirq) > 0 ) - map_domain_emuirq_pirq(d, pirq, IRQ_PT); -#endif + arch_evtchn_bind_pirq(d, pirq); out: spin_unlock(&d->event_lock); diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h index 6c00d09cea..f33c3315ac 100644 --- a/xen/include/asm-arm/irq.h +++ b/xen/include/asm-arm/irq.h @@ -47,6 +47,8 @@ int release_guest_irq(struct domain *d, unsigned int irq); void arch_move_irqs(struct vcpu *v); +#define arch_evtchn_bind_pirq(d, pirq) ((void)((d) + (pirq))) + /* Set IRQ type for an SPI */ int irq_set_spi_type(unsigned int spi, unsigned int type); diff --git a/xen/include/xen/irq.h b/xen/include/xen/irq.h index 9e0155c176..0aa817e266 100644 --- a/xen/include/xen/irq.h +++ b/xen/include/xen/irq.h @@ -172,4 +172,8 @@ unsigned int set_desc_affinity(struct irq_desc *, const cpumask_t *); unsigned int arch_hwdom_irqs(domid_t); #endif +#ifndef arch_evtchn_bind_pirq +void arch_evtchn_bind_pirq(struct domain *, int pirq); +#endif + #endif /* __XEN_IRQ_H__ */